/*
 * this header file defines the ModularUtil class
 */
#ifndef __CCCC_MOD_UTIL_H
#define __CCCC_MOD_UTIL_H

#include <string>
#include <dirent.h>
#include <sys/stat.h>
#include <list>
#include "cccc_mod_module_tree.h"
#include "cccc_mod_sinfile.h"
#include "cccc_itm.h"
#include "cccc_opt.h"
#include "cccc_met.h"
#include "cccc_db.h"
#include "cccc_utl.h"
#include "cccc_htm.h"
#include "cccc_xml.h"

#include "CParser.h"
#include "CLexer.h"
using namespace std;

int LEVEL_COUNT = -1; //count the dir level while scanning
const string LEVEL_MODULE[] = { "ROOT", "COMPONENT", "MODULE", "SUBMODULE" };
const string VIO_LEVEL_MODULE = "LEVEL_TOO_DEEP_MODULE";
const string base_language = "c";
int FileParsed;
class CParser;

vector<string> * getStrVec(string str) {
	vector<string> * ret = new vector<string> ();
	int i;
	int start = 0;
	for (i = 0; i < str.length(); i++) {
		if (str.substr(i, 1) == " ") {
			ret->push_back(str.substr(start, i - start));
			start = i + 1;
		}
	}
	return ret;
}
vector<int> * getIntVec(vector<int> vec){
	vector<int>	* ret=new vector<int>();
	for(int i=0;i<vec.size();i++){
		ret->push_back(vec.at(i));
	}
	return ret;
}
vector<Func> * getFuncVec(vector<Func> vec){
	vector<Func> * ret=new vector<Func>();
	for(int i=0;i<vec.size();i++){
		ret->push_back(vec.at(i));
	}
	return ret;
}

class ModularUtil {
private:
	static ModularUtil * modularUtil;
	std::list<SingleFile *> *list;
	std::list<std::pair<string, string> > * file_list;
	SingleFile * currentFile;
	string currentComponent;
	string currentModule;
	string currentSubModule;
	bool isCFile(const char * filename) {
		int len = 0;
		int dotcount = 0;
		char temp;
		while (temp = filename[len++] != '\0')
			;
		len -= 2;
		return filename[len - 1] == '.' && (filename[len] == 'c'
				|| filename[len] == 'h');
	}

protected:
	ModularUtil() {

	}
	~ModularUtil() {

	}

public:

	static ModularUtil * getInstance();
	void setFileParsed(int fileParsed) {
		FileParsed = fileParsed;
	}
	int getFileParsed() {
		return FileParsed;
	}

	void setList(std::list<SingleFile *> * _list) {
		list = _list;
	}

	void setFileList(std::list<std::pair<string, string> > * filelist) {
		this->file_list = filelist;
	}

	SingleFile * getCurrentSingleFile() {
		return this->currentFile;
	}

	string getLastName(const string path) {
		int len = path.length();
		int i;
		const char* str;
		str = path.c_str();
		for (i = len; i >= 0; i--) {
			if (str[i] == '/')
				break;
		}
		return path.substr(i + 1, len);
	}

	void listDir(const string path) {
		DIR* dst;
		struct dirent *entry;
		struct stat info;
		string temp;
//		cout << "entering dir:" << path << endl;
		//printf("%s\n", path.c_str());
		if (((dst = opendir(path.c_str()))) == NULL) {
			perror("Fail to open dir");
			return;
		}/*get dst dir entry*/
		if (chdir(path.c_str()) == -1) {
			perror("Fail while changing directory");
			return;
		}/*change cwd to dst dir*/
		while ((entry = readdir(dst)) != NULL) {/*reading all the file information*/
			temp = string(entry->d_name);
			temp = path + "/" + temp;
			//printf("%s\n", entry->d_name);
			if (lstat(temp.c_str(), &info) == -1) {
				perror("Fail to get the file (%s)stat");
				continue;
			}/*getting file state*/
			if (S_ISREG(info.st_mode)) { //file
				if (isCFile(entry->d_name)){
//					printf("file:%s\n", entry->d_name);
				}
			} else if (S_ISDIR(info.st_mode)) { //directory
				if (entry->d_name[0] != '.') {
//					printf("dir:%s\n", entry->d_name);
					listDir(temp);
				}
			}
		}
//		cout << "leaving dir:" << path << endl;
	}

	ModuleTreeNode * scanAndParse(const string steroType, const string path) {
		DIR* dst;
		struct dirent *entry;
		struct stat info;
		string temp;

		LEVEL_COUNT++;
//		cout << "level count increase" << LEVEL_COUNT << endl;

		ModularAtomic * modAtom = new ModularAtomic(steroType,
				getLastName(path));
		ModuleTreeNode * moduleTreeNode = new ModuleTreeNode(path);
		moduleTreeNode->setModule(modAtom);
		if (LEVEL_COUNT >= 4) {
			AViolation * vio = new AViolation("LEVEL_TOO_DEEP_VIOLATION",
					modAtom->getModuleDef(), 0, 2);
			modAtom->addViolation(vio);
		}
//		cout << "entering dir:" << path << endl;
		switch (LEVEL_COUNT) {
		case 1:
			this ->currentComponent = getLastName(path);
			break;
		case 2:
			this ->currentModule = getLastName(path);
			break;
		case 3:
			this ->currentSubModule = getLastName(path);

		default:
			break;
		}

		modAtom->setCOMPONENT(this->currentComponent);
		modAtom->setMODULE(this->currentModule);
		modAtom->setSUBMODULE(this->currentSubModule);

//		cout << "Current Component = " << this->currentComponent << endl;
//		cout << "Current Module = " << this->currentModule << endl;
//		cout << "Current SubModule = " << this->currentSubModule << endl;
		//		if (LEVEL_COUNT == 1) {
		//			this ->currentComponent = path;
		//		}
		if (((dst = opendir(path.c_str()))) == NULL) {
			perror("Fail to open dir");
			return NULL;
		}/*get dst dir entry*/
		if (chdir(path.c_str()) == -1) {
			perror("Fail while changing directory");
			return NULL;
		}/*change cwd to dst dir*/
		while ((entry = readdir(dst)) != NULL) {/*reading all the file information*/
			temp = string(entry->d_name);
			temp = path + "/" + temp;
//			cout<<"!!!!!!!!!!"<<temp.c_str()<<endl;
			if (lstat(temp.c_str(), &info) == -1) {

				perror("Fail to get the file (%s)stat");
				continue;			// TROUBLE_MAKER_1
			}/*getting file state*/
//			cout<<"!!!!!!!!!!"<<entry->d_name<<endl;
			if (S_ISREG(info.st_mode)) { //file
				if (isCFile(entry->d_name)) {
					SingleFile *tempsf = new SingleFile(temp);
					this->currentFile = tempsf;
					tempsf->setCOMPONENT(this->currentComponent);
//					cout << "Current Component: "
//							<< currentFile->getCOMPONENT() << endl;
//					printf("file:%s\n", entry->d_name);
					ParseStore ps(tempsf->getFilename());

					string file_language = "c++.ansi";
					DLGFileInput in(tempsf->getFile());
					CLexer theLexer(&in);
					ANTLRTokenBuffer thePipe(&theLexer);
					theLexer.setToken(&currentLexerToken);
					CParser theParser(&thePipe);

					ParseUtility pu(&theParser);

					theParser.init(tempsf->getFilename(), file_language);
					theParser.traceGuessOption(-1);
					theParser.start();
					list->push_back(tempsf);
					file_list->push_back(std::pair<string, string>(
							tempsf->getFilename(), "c"));
					if (theParser.MODULE != "") {
						tempsf->setMODULE(theParser.MODULE);
						tempsf->setMODULE_DEF_LINE(theParser.mod_def_line);
					}
					if (theParser.SUBMODULE != "") {
						tempsf->setSUBMODULE(theParser.SUBMODULE);
						tempsf->setSUBMODULE_DEF_LINE(theParser.submod_def_line);
					}
//					cout << "component definition : " << tempsf->getCOMPONENT()
//							<< endl;
//					cout << "module definition : " << tempsf->getMODULE()
//							<< endl;
//					cout << "submodule definition : " << tempsf->getSUBMODULE()
//							<< endl;

					tempsf->setNumFunc(theParser.NUM_FUNCS);
					tempsf->setIncludes(getStrVec(theParser.includes));
					tempsf->setIncludeLineVec(getIntVec(theParser.include_line));
					tempsf->setFuncs(getFuncVec(theParser.funcs));
//					tempsf->setIncludeLineVec(&theParser.include_line);

//					tempsf->setVISIBILITY(theParser.VISIBILITY);
					if(theParser.VISIBILITY==""){

						tempsf->setIsNoneDefault(false);

						if(this->currentSubModule!=""){
							tempsf->setVISIBILITY("SUBMODULE");
						}else if(this->currentModule!=""){
							tempsf->setVISIBILITY("MODULE");
						}else if(this->currentComponent!=""){
							tempsf->setVISIBILITY("COMPONENT");
						}

					}else{

						tempsf->setIsNoneDefault(true);

						tempsf->setVISIBILITY(theParser.VISIBILITY);
					}


					tempsf->setLOC(theParser.sloc);
					tempsf->setCodeLineNum(theParser.codeLine);
					tempsf->setCommLineNum(theParser.comLine);
					tempsf->setSpeIfdefNum(theParser.specialIFDEF);

//					tempsf->printIncludes();

//					for(int i=0;i<tempsf->getFuncs()->size();i++){
//						(*(tempsf->getFuncs()))[i].printFunc();
//					}

//					cout << "SLOC     : " << theParser.sloc << endl;
//					cout << "CODELINE : " << theParser.codeLine << endl;
//					cout << "COMMLINE : " << theParser.comLine <<endl;
//					cout << "SPECIAL IFDEF : "<< theParser.specialIFDEF<<endl;

					FileParsed++;
					moduleTreeNode->addFile(tempsf);

//					cout << moduleTreeNode->getFileAt(0)->getSteroType()
//							<< endl;
					//cout << "file obj address:" << tempsf << endl;
//					cout << "file address:" << tempsf->getFilename() << endl;
				}
			} else if (S_ISDIR(info.st_mode)) { //directory
				if (entry->d_name[0] != '.') {
					if (LEVEL_COUNT < 4) {
//						printf("dir:%s\n", entry->d_name);
						moduleTreeNode->addChild(scanAndParse(
								LEVEL_MODULE[LEVEL_COUNT + 1], temp));
					} else {
//						printf("dir:%s\n", entry->d_name);
						moduleTreeNode->addChild(scanAndParse(VIO_LEVEL_MODULE,
								temp));
					}

				}
			}
		}
//		cout << "leaving dir:" << path << endl;
		LEVEL_COUNT--;
//		cout << "level count decrease" << LEVEL_COUNT << endl;
		return moduleTreeNode;
	}
};

ModularUtil * ModularUtil::modularUtil = NULL;

ModularUtil * ModularUtil::getInstance() {
	(modularUtil == NULL) ? modularUtil = new ModularUtil() : 0; //lazy initialization
	return modularUtil;
}

#endif

